package com.woniuxy.microcurrentserver.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.woniuxy.anno.SysOperLog;
import com.woniuxy.bean.SystemLogBean;
import com.woniuxy.constant.AmqpConst;
import com.woniuxy.constant.LogConst;
import com.woniuxy.jwt.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Description: 系统日志切面处理类
 *
 * @Auther: HanLei
 * @Date: 2021/4/8:15:31
 */
@Aspect
@Component
@Slf4j
public class SysLogAspect {

    @Autowired
    private AmqpTemplate amqpTemplate;

    private volatile JoinPoint joinPoint;
    private SystemLogBean systemLogBean; //日志对象


    //基于注解的切入点
    @Pointcut(value = "@annotation(com.woniuxy.anno.SysOperLog)")
    public void logPointCut() {
    }


    /*
     * Description : 前置通知,方法执行前通过attributes 、signature等对象获取接口信息保存到systemLogBean中
     * ChangeLog : 1. 创建 (2021/4/8 16:31 );
     * @param point
     * @return null
     */
    @Before(value = "logPointCut()")
    public void logBeforeAdvice(JoinPoint point) {
        log.info("进入前置通知...");
        try{
            this.joinPoint = point;
            //操作时间
            Date date = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String operTime = sdf.format(date);
            systemLogBean = new SystemLogBean();
            systemLogBean.setOperTime(operTime);

            //通过解析token获取用户名
            //请求上下文
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            //请求头authentication
            String authentication = request.getHeader("authentication");
            //通过jwt解析authentication(token)
            DecodedJWT verify = JWTUtil.verify(authentication);
            String operUser = verify.getClaim("memberName").as(String.class);
            systemLogBean.setOperUser(operUser);
            Signature signature = point.getSignature();
            if (signature instanceof MethodSignature) {
                String active = ((MethodSignature) signature).getMethod().getAnnotation(SysOperLog.class).action();
                String operType = ((MethodSignature) signature).getMethod().getAnnotation(SysOperLog.class).operType();
                systemLogBean.setActive(active);
                systemLogBean.setOperType(operType);
            }
        }catch (Exception e) {
            log.error("生成日志错误：{}", e.getMessage());
        }
    }


    /*
     * Description : 返回通知,方法正常返回后通过returning属性获取到返回结果封装到systemLogBean中
     * ChangeLog : 1. 创建 (2021/4/8 16:31 );
     * @param joinPoint  result
     * @return null
     */
    @AfterReturning(value = "logPointCut()", returning = "result")
    public void logReturnAdvice(JoinPoint joinPoint, Object result) {
        String str = JSONObject.toJSONString(result);;
        if (this.joinPoint == joinPoint) {
            try{
                int code = JSON.parseObject(JSON.parseObject(str).getString("code"), Integer.class);
                if (code == 200) {
                    systemLogBean.setResult(LogConst.OperResult.SUCCESS);
                }else {
                    systemLogBean.setResult(LogConst.OperResult.FAIL);
                }
                //将systemLogBean发送至日志队列
                logQueueSend(systemLogBean);
            } catch (Exception e) {
                log.error("获取操作结果错误：{}", e.getMessage());
            }
        }
    }


    /*
     * Description : 异常通知,方法发生异常后执行
     * ChangeLog : 1. 创建 (2021/4/8 16:31 );
     * @param point  throwValue
     * @return null
     */
    @AfterThrowing(value = "logPointCut()", throwing = "throwValue")
    public void logExceptionAdvice(JoinPoint joinPoint, Throwable throwValue) {
        if (this.joinPoint == joinPoint) {
            try{
                systemLogBean.setResult(LogConst.OperResult.EXCEPTION);
                //将systemLogBean发送至日志队列
                logQueueSend(systemLogBean);
            }catch (Exception e) {
                log.error("获取操作结果错误：{}", e.getMessage());
            }
        }
    }


    /*
     * Description :   异步发送日志消息
     * ChangeLog : 1. 创建 (2021/4/10 11:42 );
     * @param systemLogBean 消息对象
     * @return null
     */
    public void logQueueSend(SystemLogBean systemLogBean){
        String mes = JSON.toJSONString(systemLogBean);
        this.amqpTemplate.convertAndSend(AmqpConst.ExchangeName.LOG_EXCHANGE,"", mes);
    }
}
